/* List object unit tests.
 *
 * I have attempted to order these in a manner
 * such that a test does no require a previously
 * untested function. */
#include <list.h>
#include "CuTest.h"

/* Data type creation tests */
void TestListNew(CuTest *tc) {
	list_p list = list_new();
	
	CuAssertPtrNotNull(tc, list);
	CuAssertPtrEquals(tc, NULL, list->head);
	CuAssertPtrEquals(tc, list->head, list->cur);
	CuAssertPtrEquals(tc, NULL, list->prev);
}

void TestNodeNew(CuTest *tc) {
	char *element = "test";
	node_p node = node_new(element);

	CuAssertPtrNotNull(tc, node);
	CuAssertStrEquals(tc, element, (char *)node->element);
}

void TestNodeNew_NotPtr(CuTest *tc) {
	int element = 123;
	node_p node = node_new((void *)element);

	CuAssertIntEquals(tc, element, (int)node->element);
}

void TestNodeNew_NoCast(CuTest *tc) {
	int element = 123;
	node_p node = node_new(element);

	CuAssertIntEquals(tc, element, node->element);
}

/* Node manipulation tests */
void TestNodeGet(CuTest *tc) {
	char *element = "test";
	node_p node = node_new(element);

	CuAssertStrEquals(tc, element, node_get(node));
}

void TestNodeSet(CuTest *tc) {
	char *e1 = "foo";
	char *e2 = "bar";
	node_p node = node_new(e1);

	node_set(node, e2);

	CuAssertStrEquals(tc, e2, node_get(node));
}

/* List state tests */
void TestListIsEmpty(CuTest *tc) {
	list_p list = list_new();

	CuAssertTrue(tc, list_is_empty(list));
}

void TestListCurIsEmpty(CuTest *tc) {
	list_p list = list_new();

	CuAssertTrue(tc, list_cur_is_empty(list));
}

/* Test basic add functionality */
void TestListAdd(CuTest *tc) {
	char *element = "test";
	list_p list = list_new();
	list_p res;

	res = list_add(list, element);

	CuAssertPtrNotNull(tc, res);
}

/* OK, now we can add elements. Time to test a few
 * more list state functions */
void TestListIsEmpty_NotEmpty(CuTest *tc) {
	char *element = "test";
	list_p list = list_new();

	list_add(list, element);

	CuAssertFalse(tc, list_is_empty(list));
}

void TestListCurIsEmpty_NotEmpty(CuTest *tc) {
	char *element = "test";
	list_p list = list_new();

	list_add(list, element);

	CuAssertFalse(tc, list_cur_is_empty(list));
}

void TestListAtFirst(CuTest *tc) {
	char *element = "test";
	list_p list = list_new();
	int size = 10;
	int i;

	for (i=0; i<size; i++)
		list_add(list, element);

	CuAssertTrue(tc, list_at_first(list));
}

/* Test data retrieval */
void TestListGet(CuTest *tc) {
	char *element = "test";
	list_p list = list_new();

	list_add(list, element);

	CuAssertStrEquals(tc, element, list_get(list));
}

void TestListGet_EmptyList(CuTest *tc) {
	list_p list = list_new();

	CuAssertPtrEquals(tc, NULL, list_get(list));
}

/* List movement tests */
void TestListAdvance(CuTest *tc) {
	char *e1 = "foo";
	char *e2 = "bar";
	list_p list = list_new();

	list_add(list, e1);
	list_add(list, e2);

	list_advance(list);

	CuAssertFalse(tc, list_at_first(list));
	CuAssertStrEquals(tc, e1, list_get(list));
}

void TestListAdvance_EmptyList(CuTest *tc) {
	list_p list = list_new();

	list_advance(list);

	CuAssertTrue(tc, list_cur_is_empty(list));
}

void TestListAdvance_TooFar(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_add(list, e);
	list_add(list, e);

	while (!list_cur_is_empty(list))
		list_advance(list);

	CuAssertTrue(tc, list_cur_is_empty(list));
}

/* Last round of list state tests */
void TestListAtEnd(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_add(list, e);
	list_add(list, e);
	list_add(list, e);

	while (!list_at_end(list))
		list_advance(list);

	CuAssertTrue(tc, list_at_end(list));

	list_advance(list);

	CuAssertTrue(tc, list_cur_is_empty(list));
}

void TestListAtEnd_NotEnd(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_add(list, e);

	CuAssertFalse(tc, list_at_end(list));
}

void TestListSize(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();
	int size = 10;
	int i;

	for (i=0; i<size; i++)
		list_add(list, e);

	CuAssertIntEquals(tc, size, list_size(list));
}

void TestListSize_EmptyList(CuTest *tc) {
	list_p list = list_new();

	CuAssertFalse(tc, list_size(list));
}

/* More list movement tests */
void TestListToFirst(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_add(list, e);
	list_add(list, e);

	while (!list_at_end(list))
		list_advance(list);

	CuAssertFalse(tc, list_at_first(list));

	list_to_first(list);

	CuAssertTrue(tc, list_at_first(list));
}

/* Time to start rigorous tests on add and
 * remove functions */
void TestListAdd_EmptyNode(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_advance(list);

	CuAssertPtrEquals(tc, NULL, list_add(list, e));
}

void TestListAdd_AtFirst(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();
	int size = 5;
	int i;

	for (i=1; i<size; i++)
		list_add(list, e);
	list_to_first(list);
	list_add(list, e);

	CuAssertIntEquals(tc, size, list_size(list));
}

void TestListAdd_Insertion(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);
	list_add(list, e);
	list_add(list, e);

	list_to_first(list);
	list_advance(list);

	list_add(list, e);

	CuAssertIntEquals(tc, 4, list_size(list));
}

void TestListAdd_AtEnd(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();
	int size = 5;
	int i;

	for (i=1; i<size; i++)
		list_add(list, e);
	while (!list_at_end(list))
	       list_advance(list);
	list_add(list, e);	

	CuAssertIntEquals(tc, size, list_size(list));
}

void TestListRemove(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();

	list_add(list, e);

	CuAssertPtrNotNull(tc, list_remove(list));
	CuAssertTrue(tc, list_is_empty(list));
}

void ListRemove_EmptyList(CuTest *tc) {
	list_p list = list_new();
	CuAssertPtrEquals(tc, NULL, list_remove(list));
}

void TestListRemove_AtFirst(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();
	int size = 5;
	int i;

	for (i=0; i<size; i++) 
		list_add(list, e);

	list_to_first(list);
	list_remove(list);
	list_remove(list);

	CuAssertTrue(tc, list_at_first(list));
	CuAssertIntEquals(tc, size-2, list_size(list));
}

void TestListRemove_AtEnd(CuTest *tc) {
	char *e = "test";
	list_p list = list_new();
	int size = 5;
	int i;

	for (i=0; i<size; i++)
		list_add(list, e);
	CuAssertIntEquals(tc, size, list_size(list));
	
	while (!list_at_end(list))
		list_advance(list);

	list_remove(list);
	CuAssertIntEquals(tc, size-1, list_size(list));
	list_remove(list);
	CuAssertIntEquals(tc, size-2, list_size(list));

	CuAssertTrue(tc, list_at_end(list));
}

void TestListRemove_Cut(CuTest *tc) {
	char *e1 = "BORK";
	char *e2 = "KROB";
	list_p list = list_new();
	int size = 10;
	int i;

	for (i=0; i<size; i++) {
		if (i == 8)
			list_add(list, e2);
		else
			list_add(list, e1);
	}

	list_to_first(list);

	for (i=0; i<(size%2); i++)
		list_advance(list);

	list_remove(list);
	list_remove(list);

	CuAssertIntEquals(tc, size-2, list_size(list));
}

